/**
* Copyright 2014-2016 by Metanome Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.metanome.backend.resources;
import de.metanome.algorithm_integration.algorithm_types.BasicStatisticsAlgorithm;
import de.metanome.algorithm_integration.algorithm_types.ConditionalUniqueColumnCombinationAlgorithm;
import de.metanome.algorithm_integration.algorithm_types.FunctionalDependencyAlgorithm;
import de.metanome.algorithm_integration.algorithm_types.InclusionDependencyAlgorithm;
import de.metanome.algorithm_integration.algorithm_types.MultivaluedDependencyAlgorithm;
import de.metanome.algorithm_integration.algorithm_types.OrderDependencyAlgorithm;
import de.metanome.algorithm_integration.algorithm_types.UniqueColumnCombinationsAlgorithm;
import de.metanome.backend.algorithm_loading.AlgorithmAnalyzer;
import de.metanome.backend.algorithm_loading.AlgorithmFinder;
import de.metanome.backend.algorithm_loading.AlgorithmJarLoader;
import de.metanome.backend.algorithm_loading.FileUpload;
import de.metanome.backend.results_db.Algorithm;
import de.metanome.backend.results_db.AlgorithmType;
import de.metanome.backend.results_db.EntityStorageException;
import de.metanome.backend.results_db.HibernateUtil;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
/**
* Responsible for the database communication for algorithm and for handling all restful calls of
* algorithms.
*
* @author Tanja Bergmann
*/
@Path("algorithms")
public class AlgorithmResource implements Resource<Algorithm> {
/**
* Adds a algorithm to the database for file already existing in the algorithms directory.
*
* @param algorithm the algorithm stored in the application
*/
@POST
@Path("/store")
@Consumes("application/json")
@Produces("application/json")
public void executeDatabaseStore(Algorithm algorithm) {
try {
store(algorithm);
} catch (Exception e) {
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* Uploads algorithm into the algorithms directory and adds the algorithm to the database
*
* @param uploadedInputStream Stream of File send to Backend
* @param fileDetail Additional Meta-Information about the uploaded file
*/
@POST
@Path("/store")
@Consumes("multipart/form-data")
@Produces("application/json")
public void uploadAndExecuteStore(@FormDataParam("file") InputStream uploadedInputStream,
@FormDataParam("file") FormDataContentDisposition fileDetail) {
try {
/* Check if Algorithm already exist */
AlgorithmFinder jarFinder = new AlgorithmFinder();
/* Upload file to algorithm directory */
FileUpload fileToDisk= new FileUpload();
Boolean fileExist =
fileToDisk.writeFileToDisk(
uploadedInputStream,
fileDetail,
jarFinder.getAlgorithmDirectory());
/* Add Algorithm to the Database if newly added using Store function*/
if(!fileExist) {
Algorithm algorithm = new Algorithm(fileDetail.getFileName());
store(algorithm);
}
} catch(Exception e){
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* Adds a algorithm to the database for file already existing in the algorithms directory.
*
* @param algorithm the algorithm stored in the application
* @return the stored algorithm
*/
public Algorithm store(Algorithm algorithm) {
try {
// Load the jar and get the author and description from the algorithm
AlgorithmJarLoader loader = new AlgorithmJarLoader();
de.metanome.algorithm_integration.Algorithm jarAlgorithm =
loader.loadAlgorithm(algorithm.getFileName());
String authors = jarAlgorithm.getAuthors();
String description = jarAlgorithm.getDescription();
algorithm = setAlgorithmTypes(algorithm);
algorithm.setAuthor(authors);
algorithm.setDescription(description);
HibernateUtil.store(algorithm);
return algorithm;
} catch (Exception e) {
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* Deletes the algorithm, which has the given id, from the database.
*
* @param id the id of the algorithm, which should be deleted
*/
@DELETE
@Path("/delete/{id}")
@Override
public void delete(@PathParam("id") long id) {
try {
Algorithm algorithm = (Algorithm) HibernateUtil.retrieve(Algorithm.class, id);
HibernateUtil.delete(algorithm);
} catch (Exception e) {
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* Retrieves an Algorithm from the database.
*
* @param id the Algorithm's id
* @return the algorithm
*/
@GET
@Path("/get/{id}")
@Produces("application/json")
@Override
public Algorithm get(@PathParam("id") long id) {
try {
return (Algorithm) HibernateUtil.retrieve(Algorithm.class, id);
} catch (Exception e) {
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* @return all algorithms in the database
*/
@GET
@Produces("application/json")
@SuppressWarnings("unchecked")
@Override
public List<Algorithm> getAll() {
try {
return (List<Algorithm>) HibernateUtil.queryCriteria(Algorithm.class);
} catch (Exception e) {
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* @return all inclusion dependency algorithms in the database
*/
@GET
@Path("/inclusion-dependency-algorithms/")
@Produces("application/json")
public List<Algorithm> listInclusionDependencyAlgorithms() {
try {
return listAlgorithms(InclusionDependencyAlgorithm.class);
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* @return all unique column combination algorithms in the database
*/
@GET
@Path("/unique-column-combination-algorithms/")
@Produces("application/json")
public List<Algorithm> listUniqueColumnCombinationsAlgorithms() {
try {
return listAlgorithms(UniqueColumnCombinationsAlgorithm.class);
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* @return all conditional unique column combination algorithms in the database
*/
@GET
@Path("/conditional-unique-column-combination-algorithms/")
@Produces("application/json")
public List<Algorithm> listConditionalUniqueColumnCombinationsAlgorithms() {
try {
return listAlgorithms(ConditionalUniqueColumnCombinationAlgorithm.class);
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* @return all functional dependency algorithms in the database
*/
@GET
@Path("/functional-dependency-algorithms/")
@Produces("application/json")
public List<Algorithm> listFunctionalDependencyAlgorithms() {
try {
return listAlgorithms(FunctionalDependencyAlgorithm.class);
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* @return all order dependency algorithms in the database
*/
@GET
@Path("/order-dependency-algorithms/")
@Produces("application/json")
public List<Algorithm> listOrderDependencyAlgorithms() {
try {
return listAlgorithms(OrderDependencyAlgorithm.class);
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* @return all multivalued dependency algorithms in the database
*/
@GET
@Path("/multivalued-dependency-algorithms/")
@Produces("application/json")
public List<Algorithm> listMultivaluedDependencyAlgorithms() {
try {
return listAlgorithms(MultivaluedDependencyAlgorithm.class);
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* @return all basic statistics algorithms in the database
*/
@GET
@Path("/basic-statistics-algorithms/")
@Produces("application/json")
public List<Algorithm> listBasicStatisticsAlgorithms() {
try {
return listAlgorithms(BasicStatisticsAlgorithm.class);
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* Lists all algorithms from the database that implement a certain interface, or all if algorithm
* class is null.
*
* @param algorithmClass the implemented algorithm interface.
* @return the algorithms
* @throws de.metanome.backend.results_db.EntityStorageException if algorithms could not be listed
*/
@SuppressWarnings("unchecked")
protected List<Algorithm> listAlgorithms(Class<?>... algorithmClass)
throws EntityStorageException {
// Cannot directly use array, as some interfaces might not be relevant for query.
ArrayList<Criterion> criteria = new ArrayList<>(algorithmClass.length);
Set<Class<?>> interfaces = new HashSet<>(Arrays.asList(algorithmClass));
if (interfaces.contains(InclusionDependencyAlgorithm.class)) {
criteria.add(Restrictions.eq("ind", true));
}
if (interfaces.contains(FunctionalDependencyAlgorithm.class)) {
criteria.add(Restrictions.eq("fd", true));
}
if (interfaces.contains(UniqueColumnCombinationsAlgorithm.class)) {
criteria.add(Restrictions.eq("ucc", true));
}
if (interfaces.contains(ConditionalUniqueColumnCombinationAlgorithm.class)) {
criteria.add(Restrictions.eq("cucc", true));
}
if (interfaces.contains(OrderDependencyAlgorithm.class)) {
criteria.add(Restrictions.eq("od", true));
}
if (interfaces.contains(MultivaluedDependencyAlgorithm.class)) {
criteria.add(Restrictions.eq("mvd", true));
}
if (interfaces.contains(BasicStatisticsAlgorithm.class)) {
criteria.add(Restrictions.eq("basicStat", true));
}
return (List<Algorithm>) HibernateUtil.queryCriteria(Algorithm.class, criteria.toArray(new Criterion[criteria.size()]));
}
/**
* Lists all algorithm file names located in the algorithm folder.
*
* @return list of algorithm file names
*/
@GET
@Path("/available-algorithm-files/")
@Produces("application/json")
public List<String> listAvailableAlgorithmFiles() {
try {
AlgorithmFinder algorithmFinder = new AlgorithmFinder();
List<String> files = new ArrayList<>();
Collections.addAll(files, algorithmFinder.getAvailableAlgorithmFileNames(null));
return files;
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
/**
* Updates an algorithm in the database.
*
* @param algorithm the algorithm
* @return the updated algorithm
*/
@POST
@Path("/update")
@Consumes("application/json")
@Produces("application/json")
@Override
public Algorithm update(Algorithm algorithm) {
try {
// Load the jar and get the author and description from the algorithm
AlgorithmJarLoader loader = new AlgorithmJarLoader();
de.metanome.algorithm_integration.Algorithm jarAlgorithm = loader.loadAlgorithm(algorithm.getFileName());
String authors = jarAlgorithm.getAuthors();
String description = jarAlgorithm.getDescription();
algorithm = setAlgorithmTypes(algorithm);
algorithm.setAuthor(authors);
algorithm.setDescription(description);
HibernateUtil.update(algorithm);
return algorithm;
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
private Algorithm setAlgorithmTypes(Algorithm algorithm) throws Exception {
AlgorithmAnalyzer analyzer = new AlgorithmAnalyzer(algorithm.getFileName());
algorithm.setFd(analyzer.hasType(AlgorithmType.FD));
algorithm.setInd(analyzer.hasType(AlgorithmType.IND));
algorithm.setUcc(analyzer.hasType(AlgorithmType.UCC));
algorithm.setCucc(analyzer.hasType(AlgorithmType.CUCC));
algorithm.setOd(analyzer.hasType(AlgorithmType.OD));
algorithm.setMvd(analyzer.hasType(AlgorithmType.MVD));
algorithm.setBasicStat(analyzer.hasType(AlgorithmType.BASIC_STAT));
algorithm.setDatabaseConnection(analyzer.hasType(AlgorithmType.DB_CONNECTION));
algorithm.setFileInput(analyzer.hasType(AlgorithmType.FILE_INPUT));
algorithm.setRelationalInput(analyzer.hasType(AlgorithmType.RELATIONAL_INPUT));
algorithm.setTableInput(analyzer.hasType(AlgorithmType.TABLE_INPUT));
return algorithm;
}
@GET
@Path("/algorithms-for-file-inputs")
@Produces("application/json")
@SuppressWarnings("unchecked")
public List<Algorithm> getAlgorithmsForFileInputs() {
try {
ArrayList<Criterion> criteria = new ArrayList<>();
criteria.add(Restrictions.eq("fileInput", true));
List<Algorithm> algorithms = (List<Algorithm>) HibernateUtil
.queryCriteria(Algorithm.class, criteria.toArray(new Criterion[criteria.size()]));
criteria = new ArrayList<>();
criteria.add(Restrictions.eq("relationalInput", true));
List<Algorithm> storedAlgorithms = (List<Algorithm>) HibernateUtil.queryCriteria(Algorithm.class, criteria.toArray(new Criterion[criteria.size()]));
if (algorithms != null) {
algorithms.addAll(storedAlgorithms);
}
return algorithms;
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
@GET
@Path("/algorithms-for-table-inputs")
@Produces("application/json")
@SuppressWarnings("unchecked")
public List<Algorithm> getAlgorithmsForTableInputs() {
try {
ArrayList<Criterion> criteria = new ArrayList<>();
criteria.add(Restrictions.eq("fileInput", true));
List<Algorithm> algorithms = (List<Algorithm>) HibernateUtil
.queryCriteria(Algorithm.class, criteria.toArray(new Criterion[criteria.size()]));
criteria = new ArrayList<>();
criteria.add(Restrictions.eq("relationalInput", true));
List<Algorithm> storedAlgorithms = (List<Algorithm>) HibernateUtil.queryCriteria(Algorithm.class, criteria.toArray(new Criterion[criteria.size()]));
if (algorithms != null) {
algorithms.addAll(storedAlgorithms);
}
return algorithms;
} catch (Exception e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
@GET
@Path("/algorithms-for-database-connections")
@Produces("application/json")
@SuppressWarnings("unchecked")
public List<Algorithm> getAlgorithmsForDatabaseConnections() {
try {
ArrayList<Criterion> criteria = new ArrayList<>();
criteria.add(Restrictions.eq("databaseConnection", true));
return (List<Algorithm>) HibernateUtil
.queryCriteria(Algorithm.class, criteria.toArray(new Criterion[criteria.size()]));
} catch (EntityStorageException e) {
e.printStackTrace();
throw new WebException(e, Response.Status.BAD_REQUEST);
}
}
}